package com.dzsw.e2p.sample;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;

import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;

public class DrawTableUtils {

    /**
     * 页边距
     */
    private static final float PADDING = 30;
    /**
     * 下表格线偏移
     */
    private static final float DOWN_LINE_PADDING = 0.5f;
    /**
     * 边框宽度
     */
    private static final float BORDER_WIDTH = 1;
    /**
     * 生成PDF
     *
     * @param table pdf数据
     * @throws IOException
     */
    public static void createDocument(PdfTable table) throws IOException {

        // 初始化文档
        PDDocument document = new PDDocument();
        final PDPage page = new PDPage(PDRectangle.A4);
        document.addPage(page);
        // 字体
        String fontName = table.getFont();
        InputStream inFont = DrawTableUtils.class.getClassLoader().getResourceAsStream(fontName);
        PDType0Font font = PDType0Font.load(document, inFont);
        // 页
        int pageNum = 1;
        // 初始化文档位置
        DrawTableUtils.Position position = new DrawTableUtils.Position(PADDING, page.getMediaBox().getHeight() - PADDING, 0);
        PDPageContentStream contentStream = new PDPageContentStream(document, page);

        for (PdfRow row : table.getRows()) {

            // 分页
            if (position.startY <= PADDING * 2) {

                pageNum++;
                PDPage pdPage = new PDPage(PDRectangle.A4);
                document.addPage(pdPage);
                position.startY = page.getMediaBox().getHeight() - PADDING;
                contentStream.close();
                contentStream = new PDPageContentStream(document, pdPage);
            }

            drawLine(row, document, contentStream, position, font);

            if (row.isDownBorder()) {

                drawDrownBorder(contentStream, page, row, position);
            }


        }
        contentStream.close();
        // 页脚
        drawPageFoot(document, pageNum, font);
        // 保存文档
        document.save("D:/mypdf.pdf");
        document.close();
    }


    /**
     * 生成表格下框，以行为单位
     *
     * @param contentStream 流
     * @param page          页
     * @param row           行
     * @param position      位置
     * @throws IOException
     */
    private static void drawDrownBorder(PDPageContentStream contentStream, PDPage page, PdfRow row, DrawTableUtils.Position position) throws IOException {

        contentStream.setStrokingColor(row.getBoderColor());
        contentStream.setLineWidth(BORDER_WIDTH);
        contentStream.setLineDashPattern(row.getBorderStyle().getPattern(), row.getBorderStyle().getPhase());
        contentStream.moveTo(PADDING, position.startY + position.titleHeight / 4 - row.getHeight() / 2 + DOWN_LINE_PADDING);
        contentStream.lineTo(page.getMediaBox().getWidth() - PADDING, position.startY + position.titleHeight / 4 - row.getHeight() / 2 + DOWN_LINE_PADDING);
        contentStream.stroke();
    }
    /**
     * 生成一行中每一列数据
     *
     * @param row           行
     * @param document      文档
     * @param contentStream 流
     * @param position      位置
     * @param font          字体
     * @throws IOException
     */
    public static void drawLine(PdfRow row, PDDocument document, PDPageContentStream contentStream, DrawTableUtils.Position position, PDType0Font font) throws IOException {

        // 更新Y轴位置
        position.startY -= row.getHeight();
        for (PdfColumn column : row.getPdfColumns()) {

            // 添加图片
            if (column.getColumnImage() != null) {

                PdfColumnImage columnImage = column.getColumnImage();
                final byte[] imageByte = IOUtils.toByteArray(Objects.requireNonNull(DrawTableUtils.class.getClassLoader().getResourceAsStream(columnImage.getImage())));
                final PDImageXObject image = PDImageXObject.createFromByteArray(document, imageByte, columnImage.getImage());
                contentStream.drawImage(image, columnImage.getX(), columnImage.getY(), columnImage.getWidth(), columnImage.getHeight());
            } else {

                // 背景
                if (column.getBackGround() != Color.WHITE) {

                    // 文字高度
                    position.titleHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * column.getFontSize();
                    // 背景高度，取行高
                    contentStream.setLineWidth(row.getHeight());
                    contentStream.setStrokingColor(column.getBackGround());
                    // 实线无间隔
                    contentStream.setLineDashPattern(BorderStyle.SOLID.getPattern(), BorderStyle.SOLID.getPhase());
                    // 设置Y轴起始位置，文字在背景色中间
                    contentStream.moveTo(position.startX + column.getOffset(), position.startY + position.titleHeight / 4);
                    contentStream.lineTo(position.startX + column.getOffset() + column.getWidth(), position.startY + position.titleHeight / 4);
                    contentStream.stroke();
                }
                // 左边框
                if (column.isLeftBorder()) {

                    position.titleHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * column.getFontSize();
                    // 设置宽度
                    contentStream.setLineWidth(BORDER_WIDTH);
                    contentStream.setStrokingColor(column.getBorderColor());
                    // 实线无间隔
                    contentStream.setLineDashPattern(BorderStyle.SOLID.getPattern(), BorderStyle.SOLID.getPhase());
                    // 设置左边框位置，与背景色对齐
                    contentStream.moveTo(position.startX + column.getOffset(), position.startY + position.titleHeight / 4 - row.getHeight() / 2);
                    contentStream.lineTo(position.startX + column.getOffset(), position.startY + position.titleHeight / 4 + row.getHeight() / 2);
                    contentStream.stroke();
                }
                // 右边框
                if (column.isRightBorder()) {

                    position.titleHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * column.getFontSize();
                    // 设置宽度
                    contentStream.setLineWidth(BORDER_WIDTH);
                    contentStream.setStrokingColor(column.getBorderColor());
                    // 实线无间隔
                    contentStream.setLineDashPattern(BorderStyle.SOLID.getPattern(), BorderStyle.SOLID.getPhase());
                    // 设置左边框位置，与背景色对齐
                    contentStream.moveTo(position.startX + column.getOffset() + column.getWidth(), position.startY + position.titleHeight / 4 - row.getHeight() / 2);
                    contentStream.lineTo(position.startX + column.getOffset() + column.getWidth(), position.startY + position.titleHeight / 4 + row.getHeight() / 2);
                    contentStream.stroke();
                }
                float titleWidth = font.getStringWidth(column.getName() == null ? "" : column.getName()) / 1000 * column.getFontSize();
                // 自动换行
                if (column.isAutoLine()) {

                    if (titleWidth > column.getWidth()) {

                        // 切分行数
                        int ceil = (int) Math.ceil(titleWidth / column.getWidth());
                        int currentCel = ceil;
                        float hi = row.getHeight() / ceil;
                        String[] split = column.getName().split(" ");
                        StringBuilder builder = new StringBuilder();
                        float len = 0;
                        for (int i = 0; i < split.length; i++) {

                            len += font.getStringWidth(split[i] + " ") / 1000 * column.getFontSize();
                            builder.append(split[i]).append(" ");
                            if ((i == split.length - 1 && len > 0) || len + font.getStringWidth(split[i + 1]) / 1000 * column.getFontSize() >= column.getWidth()) {

                                // 写入分行数据
                                DrawTableUtils.Position aPosition = new DrawTableUtils.Position(position.startX, position.startY + hi * (currentCel - 1) - position.getTitleHeight() / 4, position.getTitleHeight());
                                PdfColumn aColumn = PdfColumn.builder().align(column.getAlign()).fontSize(column.getFontSize() / ceil * 1.8f).name(builder.toString()).width(column.getWidth()).offset(column.getOffset()).block(column.isBlock()).build();
                                float pWidth = font.getStringWidth(aColumn.getName() == null ? "" : aColumn.getName()) / 1000 * aColumn.getFontSize();
                                drawMuLine(contentStream, aPosition, aColumn, pWidth, font);
                                currentCel--;
                                builder.setLength(0);
                                len = 0;
                            }
                        }
                    }
                } else {

                    // 自动宽度
                    if (column.isAutoWidth()){

                        column.setWidth(titleWidth);
                    }
                    drawMuLine(contentStream, position, column, titleWidth, font);

                }

            }
            // 更新X轴位置
            position.startX = position.startX + column.getWidth() + column.getOffset();
        }
        position.startX = PADDING;
    }

    private static void drawMuLine(PDPageContentStream contentStream, DrawTableUtils.Position position, PdfColumn column, float titleWidth, PDType0Font normalFont) throws IOException {

        // 文字
        contentStream.beginText();
        contentStream.setFont(normalFont, column.getFontSize());
        contentStream.setNonStrokingColor(column.getTextColor());

        HorizontalAlignment align = column.getAlign();
        if (align == HorizontalAlignment.CENTER) {

            // 居中
            contentStream.newLineAtOffset((column.getWidth() - titleWidth) / 2 + position.startX + column.getOffset(), position.startY);
        } else if (align == HorizontalAlignment.LEFT) {

            // 居左
            contentStream.newLineAtOffset(position.startX + column.getOffset(), position.startY);
        } else if (align == HorizontalAlignment.RIGHT) {

            // 居右
            contentStream.newLineAtOffset(position.startX + column.getOffset() + column.getWidth() - titleWidth, position.startY);
        }

        contentStream.showText(column.getName() == null ? "" : column.getName());
        contentStream.endText();

        //  加粗使用偏移方法
        if (column.isBlock()) {

            drawBlockText(contentStream, position, column, titleWidth);
        }

    }

    private static void drawBlockText(PDPageContentStream contentStream, DrawTableUtils.Position position, PdfColumn pdfColumn, float titleWidth) throws IOException {

        float offset = pdfColumn.getFontSize() / 50;

        float x=0;
        float y=0;
        if (pdfColumn.getAlign() == HorizontalAlignment.CENTER) {

            // 居中
            x=(pdfColumn.getWidth() - titleWidth) / 2 + position.startX + pdfColumn.getOffset();
            y=position.startY;
        } else if (pdfColumn.getAlign() == HorizontalAlignment.LEFT) {

            // 居左
            x=position.startX + pdfColumn.getOffset();
            y= position.startY;
        } else if (pdfColumn.getAlign() == HorizontalAlignment.RIGHT) {

            // 居右
            x=position.startX + pdfColumn.getOffset() + pdfColumn.getWidth() - titleWidth;
            y=position.startY;
            offset=-offset;
        }

        // 水平
        contentStream.beginText();
        contentStream.newLineAtOffset(x+offset, y);
        contentStream.showText(pdfColumn.getName() == null ? "" : pdfColumn.getName());
        contentStream.endText();
        // 水平上
        contentStream.beginText();
        contentStream.newLineAtOffset(x+offset, y+Math.abs(offset));
        contentStream.showText(pdfColumn.getName() == null ? "" : pdfColumn.getName());
        contentStream.endText();
        // 垂直
        contentStream.beginText();
        contentStream.newLineAtOffset(x, y+Math.abs(offset));
        contentStream.showText(pdfColumn.getName() == null ? "" : pdfColumn.getName());
        contentStream.endText();
    }

    /**
     * 页脚
     * @param document 文档
     * @param pageNum 文档页数
     * @param font 字体
     * @throws IOException
     */
    private static void drawPageFoot(PDDocument document, int pageNum, PDType0Font font) throws IOException {


        String text = "xxxxxxxxxxxxxxxxxxxx                                      xxxxxxxxxxxxxxxxxxxxxx                                                       ";
        for (int i = 0; i < pageNum; i++) {

            PDPage page = document.getPage(i);
            PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND,true);
            contentStream.beginText();
            contentStream.setFont(font, 10);
            contentStream.setNonStrokingColor(Color.GRAY);
            contentStream.newLineAtOffset(50, 30);
            contentStream.showText(text + (i + 1) + "/" + pageNum);
            contentStream.endText();
            contentStream.close();
        }
    }

    @Data
    @AllArgsConstructor
    static class Position {

        float startX;
        float startY;
        float titleHeight;
    }
}
